/*
 * ===========================================
 * Java Pdf Extraction Decoding Access Library
 * ===========================================
 *
 * Project Info:  http://www.idrsolutions.com
 * Help section for developers at http://www.idrsolutions.com/java-pdf-library-support/
 *
 * (C) Copyright 1997-2013, IDRsolutions and Contributors.
 *
 * 	This file is part of JPedal
 *
     This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA


 *
 * ---------------
 * PrintfFormat.java
 * ---------------
 */

package org.jpedal.sun;

//
// (c) 2000 Sun Microsystems, Inc.
// ALL RIGHTS RESERVED
// 
// License Grant-
// 
// 
// Permission to use, copy, modify, and distribute this Software and its 
// documentation for NON-COMMERCIAL or COMMERCIAL purposes and without fee is 
// hereby granted.  
// 
// This Software is provided "AS IS".  All express warranties, including any 
// implied warranty of merchantability, satisfactory quality, fitness for a 
// particular purpose, or non-infringement, are disclaimed, except to the extent 
// that such disclaimers are held to be legally invalid.
// 
// You acknowledge that Software is not designed, licensed or intended for use in 
// the design, construction, operation or maintenance of any nuclear facility 
// ("High Risk Activities").  Sun disclaims any express or implied warranty of 
// fitness for such uses.  
//
// Please refer to the file http://www.sun.com/policies/trademarks/ for further 
// important trademark information and to 
// http://java.sun.com/nav/business/index.html for further important licensing 
// information for the Java Technology.
//

import java.text.DecimalFormatSymbols;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Locale;

/**
 * PrintfFormat allows the formatting of an array of objects embedded within a string. Primitive types must be passed using wrapper types. The
 * formatting is controlled by a control string.
 * <p>
 * A control string is a Java string that contains a control specification. The control specification starts at the first percent sign (%) in the
 * string, provided that this percent sign
 * <ol>
 * <li>is not escaped protected by a matching % or is not an escape % character,
 * <li>is not at the end of the format string, and
 * <li>precedes a sequence of characters that parses as a valid control specification.
 * </ol>
 * </p>
 * <p>
 * A control specification usually takes the form:
 * 
 * <pre>
 * % ['-+ #0]* [0..9]* { . [0..9]* }+
 *                { [hlL] }+ [idfgGoxXeEcs]
 * </pre>
 * 
 * There are variants of this basic form that are discussed below.
 * </p>
 * <p>
 * The format is composed of zero or more directives defined as follows:
 * <ul>
 * <li>ordinary characters, which are simply copied to the output stream;
 * <li>escape sequences, which represent non-graphic characters; and
 * <li>conversion specifications, each of which results in the fetching of zero or more arguments.
 * </ul>
 * </p>
 * <p>
 * The results are undefined if there are insufficient arguments for the format. Usually an unchecked exception will be thrown. If the format is
 * exhausted while arguments remain, the excess arguments are evaluated but are otherwise ignored. In format strings containing the % form of
 * conversion specifications, each argument in the argument list is used exactly once.
 * </p>
 * <p>
 * Conversions can be applied to the <code>n</code>th argument after the format in the argument list, rather than to the next unused argument. In this
 * case, the conversion characer % is replaced by the sequence %<code>n</code>$, where <code>n</code> is a decimal integer giving the position of the
 * argument in the argument list.
 * </p>
 * <p>
 * In format strings containing the %<code>n</code>$ form of conversion specifications, each argument in the argument list is used exactly once.
 * </p>
 * 
 * <h4>Escape Sequences</h4>
 * <p>
 * The following table lists escape sequences and associated actions on display devices capable of the action.
 * <table>
 * <tr>
 * <th align=left>Sequence</th>
 * <th align=left>Name</th>
 * <th align=left>Description</th>
 * </tr>
 * <tr>
 * <td>\\</td>
 * <td>backlash</td>
 * <td>None.</td>
 * </tr>
 * <tr>
 * <td>\a</td>
 * <td>alert</td>
 * <td>Attempts to alert the user through audible or visible notification.</td>
 * </tr>
 * <tr>
 * <td>\b</td>
 * <td>backspace</td>
 * <td>Moves the printing position to one column before the current position, unless the current position is the start of a line.</td>
 * </tr>
 * <tr>
 * <td>\f</td>
 * <td>form-feed</td>
 * <td>Moves the printing position to the initial printing position of the next logical page.</td>
 * </tr>
 * <tr>
 * <td>\n</td>
 * <td>newline</td>
 * <td>Moves the printing position to the start of the next line.</td>
 * </tr>
 * <tr>
 * <td>\r</td>
 * <td>carriage-return</td>
 * <td>Moves the printing position to the start of the current line.</td>
 * </tr>
 * <tr>
 * <td>\t</td>
 * <td>tab</td>
 * <td>Moves the printing position to the next implementation- defined horizontal tab position.</td>
 * </tr>
 * <tr>
 * <td>\v</td>
 * <td>vertical-tab</td>
 * <td>Moves the printing position to the start of the next implementation-defined vertical tab position.</td>
 * </tr>
 * </table>
 * </p>
 * <h4>Conversion Specifications</h4>
 * <p>
 * Each conversion specification is introduced by the percent sign character (%). After the character %, the following appear in sequence:
 * </p>
 * <p>
 * Zero or more flags (in any order), which modify the meaning of the conversion specification.
 * </p>
 * <p>
 * An optional minimum field width. If the converted value has fewer characters than the field width, it will be padded with spaces by default on the
 * left; t will be padded on the right, if the left- adjustment flag (-), described below, is given to the field width. The field width takes the form
 * of a decimal integer. If the conversion character is s, the field width is the the minimum number of characters to be printed.
 * </p>
 * <p>
 * An optional precision that gives the minumum number of digits to appear for the d, i, o, x or X conversions (the field is padded with leading
 * zeros); the number of digits to appear after the radix character for the e, E, and f conversions, the maximum number of significant digits for the
 * g and G conversions; or the maximum number of characters to be written from a string is s and S conversions. The precision takes the form of an
 * optional decimal digit string, where a null digit string is treated as 0. If a precision appears with a c conversion character the precision is
 * ignored.
 * </p>
 * <p>
 * An optional h specifies that a following d, i, o, x, or X conversion character applies to a type short argument (the argument will be promoted
 * according to the integral promotions and its value converted to type short before printing).
 * </p>
 * <p>
 * An optional l (ell) specifies that a following d, i, o, x, or X conversion character applies to a type long argument.
 * </p>
 * <p>
 * A field width or precision may be indicated by an asterisk (*) instead of a digit string. In this case, an integer argument supplised the field
 * width precision. The argument that is actually converted is not fetched until the conversion letter is seen, so the the arguments specifying field
 * width or precision must appear before the argument (if any) to be converted. If the precision argument is negative, it will be changed to zero. A
 * negative field width argument is taken as a - flag, followed by a positive field width.
 * </p>
 * <p>
 * In format strings containing the %<code>n</code>$ form of a conversion specification, a field width or precision may be indicated by the sequence *
 * <code>m</code>$, where m is a decimal integer giving the position in the argument list (after the format argument) of an integer argument
 * containing the field width or precision.
 * </p>
 * <p>
 * The format can contain either numbered argument specifications (that is, %<code>n</code>$ and *<code>m</code>$), or unnumbered argument
 * specifications (that is % and *), but normally not both. The only exception to this is that %% can be mixed with the %<code>n</code>$ form. The
 * results of mixing numbered and unnumbered argument specifications in a format string are undefined.
 * </p>
 * 
 * <h4>Flag Characters</h4>
 * <p>
 * The flags and their meanings are:
 * </p>
 * <dl>
 * <dt>'
 * <dd>integer portion of the result of a decimal conversion (%i, %d, %f, %g, or %G) will be formatted with thousands' grouping characters. For other
 * conversions the flag is ignored. The non-monetary grouping character is used.
 * <dt>-
 * <dd>result of the conversion is left-justified within the field. (It will be right-justified if this flag is not specified).</td></tr>
 * <dt>+
 * <dd>result of a signed conversion always begins with a sign (+ or -). (It will begin with a sign only when a negative value is converted if this
 * flag is not specified.)
 * <dt>&lt;space&gt;
 * <dd>If the first character of a signed conversion is not a sign, a space character will be placed before the result. This means that if the space
 * character and + flags both appear, the space flag will be ignored.
 * <dt>#
 * <dd>value is to be converted to an alternative form. For c, d, i, and s conversions, the flag has no effect. For o conversion, it increases the
 * precision to force the first digit of the result to be a zero. For x or X conversion, a non-zero result has 0x or 0X prefixed to it, respectively.
 * For e, E, f, g, and G conversions, the result always contains a radix character, even if no digits follow the radix character (normally, a decimal
 * point appears in the result of these conversions only if a digit follows it). For g and G conversions, trailing zeros will not be removed from the
 * result as they normally are.
 * <dt>0
 * <dd>d, i, o, x, X, e, E, f, g, and G conversions, leading zeros (following any indication of sign or base) are used to pad to the field width; no
 * space padding is performed. If the 0 and - flags both appear, the 0 flag is ignored. For d, i, o, x, and X conversions, if a precision is
 * specified, the 0 flag will be ignored. For c conversions, the flag is ignored.
 * </dl>
 * 
 * <h4>Conversion Characters</h4>
 * <p>
 * Each conversion character results in fetching zero or more arguments. The results are undefined if there are insufficient arguments for the format.
 * Usually, an unchecked exception will be thrown. If the format is exhausted while arguments remain, the excess arguments are ignored.
 * </p>
 * 
 * <p>
 * The conversion characters and their meanings are:
 * </p>
 * <dl>
 * <dt>d,i
 * <dd>The int argument is converted to a signed decimal in the style [-]dddd. The precision specifies the minimum number of digits to appear; if the
 * value being converted can be represented in fewer digits, it will be expanded with leading zeros. The default precision is 1. The result of
 * converting 0 with an explicit precision of 0 is no characters.
 * <dt>o
 * <dd>The int argument is converted to unsigned octal format in the style ddddd. The precision specifies the minimum number of digits to appear; if
 * the value being converted can be represented in fewer digits, it will be expanded with leading zeros. The default precision is 1. The result of
 * converting 0 with an explicit precision of 0 is no characters.
 * <dt>x
 * <dd>The int argument is converted to unsigned hexadecimal format in the style dddd; the letters abcdef are used. The precision specifies the
 * minimum numberof digits to appear; if the value being converted can be represented in fewer digits, it will be expanded with leading zeros. The
 * default precision is 1. The result of converting 0 with an explicit precision of 0 is no characters.
 * <dt>X
 * <dd>Behaves the same as the x conversion character except that letters ABCDEF are used instead of abcdef.
 * <dt>f
 * <dd>The floating point number argument is written in decimal notation in the style [-]ddd.ddd, where the number of digits after the radix character
 * (shown here as a decimal point) is equal to the precision specification. A Locale is used to determine the radix character to use in this format.
 * If the precision is omitted from the argument, six digits are written after the radix character; if the precision is explicitly 0 and the # flag is
 * not specified, no radix character appears. If a radix character appears, at least 1 digit appears before it. The value is rounded to the
 * appropriate number of digits.
 * <dt>e,E
 * <dd>The floating point number argument is written in the style [-]d.ddde{+-}dd (the symbols {+-} indicate either a plus or minus sign), where there
 * is one digit before the radix character (shown here as a decimal point) and the number of digits after it is equal to the precision. A Locale is
 * used to determine the radix character to use in this format. When the precision is missing, six digits are written after the radix character; if
 * the precision is 0 and the # flag is not specified, no radix character appears. The E conversion will produce a number with E instead of e
 * introducing the exponent. The exponent always contains at least two digits. However, if the value to be written requires an exponent greater than
 * two digits, additional exponent digits are written as necessary. The value is rounded to the appropriate number of digits.
 * <dt>g,G
 * <dd>The floating point number argument is written in style f or e (or in sytle E in the case of a G conversion character), with the precision
 * specifying the number of significant digits. If the precision is zero, it is taken as one. The style used depends on the value converted: style e
 * (or E) will be used only if the exponent resulting from the conversion is less than -4 or greater than or equal to the precision. Trailing zeros
 * are removed from the result. A radix character appears only if it is followed by a digit.
 * <dt>c,C
 * <dd>The integer argument is converted to a char and the result is written.
 * 
 * <dt>s,S
 * <dd>The argument is taken to be a string and bytes from the string are written until the end of the string or the number of bytes indicated by the
 * precision specification of the argument is reached. If the precision is omitted from the argument, it is taken to be infinite, so all characters up
 * to the end of the string are written.
 * <dt>%
 * <dd>Write a % character; no argument is converted.
 * </dl>
 * <p>
 * If a conversion specification does not match one of the above forms, an IllegalArgumentException is thrown and the instance of PrintfFormat is not
 * created.
 * </p>
 * <p>
 * If a floating point value is the internal representation for infinity, the output is [+]Infinity, where Infinity is either Infinity or Inf,
 * depending on the desired output string length. Printing of the sign follows the rules described above.
 * </p>
 * <p>
 * If a floating point value is the internal representation for "not-a-number," the output is [+]NaN. Printing of the sign follows the rules described
 * above.
 * </p>
 * <p>
 * In no case does a non-existent or small field width cause truncation of a field; if the result of a conversion is wider than the field width, the
 * field is simply expanded to contain the conversion result.
 * </p>
 * <p>
 * The behavior is like printf. One exception is that the minimum number of exponent digits is 3 instead of 2 for e and E formats when the optional L
 * is used before the e, E, g, or G conversion character. The optional L does not imply conversion to a long long double.
 * </p>
 * <p>
 * The biggest divergence from the C printf specification is in the use of 16 bit characters. This allows the handling of characters beyond the small
 * ASCII character set and allows the utility to interoperate correctly with the rest of the Java runtime environment.
 * </p>
 * <p>
 * Omissions from the C printf specification are numerous. All the known omissions are present because Java never uses bytes to represent characters
 * and does not have pointers:
 * </p>
 * <ul>
 * <li>%c is the same as %C.
 * <li>%s is the same as %S.
 * <li>u, p, and n conversion characters.
 * <li>%ws format.
 * <li>h modifier applied to an n conversion character.
 * <li>l (ell) modifier applied to the c, n, or s conversion characters.
 * <li>ll (ell ell) modifier to d, i, o, u, x, or X conversion characters.
 * <li>ll (ell ell) modifier to an n conversion character.
 * <li>c, C, d,i,o,u,x, and X conversion characters apply to Byte, Character, Short, Integer, Long types.
 * <li>f, e, E, g, and G conversion characters apply to Float and Double types.
 * <li>s and S conversion characters apply to String types.
 * <li>All other reference types can be formatted using the s or S conversion characters only.
 * </ul>
 * <p>
 * Most of this specification is quoted from the Unix man page for the sprintf utility.
 * </p>
 * 
 * @author Allan Jacobs
 * @version 1 Release 1: Initial release. Release 2: Asterisk field widths and precisions %n$ and *m$ Bug fixes g format fix (2 digits in e form
 *          corrupt) rounding in f format implemented round up when digit not printed is 5 formatting of -0.0f round up/down when last digits are
 *          50000...
 */
public class PrintfFormat {
	/**
	 * Constructs an array of control specifications possibly preceded, separated, or followed by ordinary strings. Control strings begin with
	 * unpaired percent signs. A pair of successive percent signs designates a single percent sign in the format.
	 * 
	 * @param fmtArg
	 *            Control string.
	 * @exception IllegalArgumentException
	 *                if the control string is null, zero length, or otherwise malformed.
	 */
	public PrintfFormat(String fmtArg) throws IllegalArgumentException {
		this(Locale.getDefault(), fmtArg);
	}

	/**
	 * Constructs an array of control specifications possibly preceded, separated, or followed by ordinary strings. Control strings begin with
	 * unpaired percent signs. A pair of successive percent signs designates a single percent sign in the format.
	 * 
	 * @param fmtArg
	 *            Control string.
	 * @exception IllegalArgumentException
	 *                if the control string is null, zero length, or otherwise malformed.
	 */
	public PrintfFormat(Locale locale, String fmtArg) throws IllegalArgumentException {
		this.dfs = new DecimalFormatSymbols(locale);
		int ePos = 0;
		ConversionSpecification sFmt = null;
		String unCS = this.nonControl(fmtArg, 0);
		if (unCS != null) {
			sFmt = new ConversionSpecification();
			sFmt.setLiteral(unCS);
			this.vFmt.add(sFmt);
		}
		while (this.cPos != -1 && this.cPos < fmtArg.length()) {
			for (ePos = this.cPos + 1; ePos < fmtArg.length(); ePos++) {
				char c = 0;
				c = fmtArg.charAt(ePos);
				if (c == 'i') break;
				if (c == 'd') break;
				if (c == 'f') break;
				if (c == 'g') break;
				if (c == 'G') break;
				if (c == 'o') break;
				if (c == 'x') break;
				if (c == 'X') break;
				if (c == 'e') break;
				if (c == 'E') break;
				if (c == 'c') break;
				if (c == 's') break;
				if (c == '%') break;
			}
			ePos = Math.min(ePos + 1, fmtArg.length());
			sFmt = new ConversionSpecification(fmtArg.substring(this.cPos, ePos));
			this.vFmt.add(sFmt);
			unCS = this.nonControl(fmtArg, ePos);
			if (unCS != null) {
				sFmt = new ConversionSpecification();
				sFmt.setLiteral(unCS);
				this.vFmt.add(sFmt);
			}
		}
	}

	/**
	 * Return a substring starting at <code>start</code> and ending at either the end of the String <code>s</code>, the next unpaired percent sign, or
	 * at the end of the String if the last character is a percent sign.
	 * 
	 * @param s
	 *            Control string.
	 * @param start
	 *            Position in the string <code>s</code> to begin looking for the start of a control string.
	 * @return the substring from the start position to the beginning of the control string.
	 */
	private String nonControl(String s, int start) {
		// String ret="";
		this.cPos = s.indexOf('%', start);
		if (this.cPos == -1) this.cPos = s.length();
		return s.substring(start, this.cPos);
	}

	/**
	 * Format an array of objects. Byte, Short, Integer, Long, Float, Double, and Character arguments are treated as wrappers for primitive types.
	 * 
	 * @param o
	 *            The array of objects to format.
	 * @return The formatted String.
	 */
	public String sprintf(Object[] o) {
		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		int i = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else {
					if (cs.isPositionalSpecification()) {
						i = cs.getArgumentPosition() - 1;
						if (cs.isPositionalFieldWidth()) {
							int ifw = cs.getArgumentPositionForFieldWidth() - 1;
							cs.setFieldWidthWithArg((Integer) o[ifw]);
						}
						if (cs.isPositionalPrecision()) {
							int ipr = cs.getArgumentPositionForPrecision() - 1;
							cs.setPrecisionWithArg((Integer) o[ipr]);
						}
					}
					else {
						if (cs.isVariableFieldWidth()) {
							cs.setFieldWidthWithArg((Integer) o[i]);
							i++;
						}
						if (cs.isVariablePrecision()) {
							cs.setPrecisionWithArg((Integer) o[i]);
							i++;
						}
					}
					if (o[i] instanceof Byte) sb.append(cs.internalsprintf(((Byte) o[i]).byteValue()));
					else
						if (o[i] instanceof Short) sb.append(cs.internalsprintf(((Short) o[i]).shortValue()));
						else
							if (o[i] instanceof Integer) sb.append(cs.internalsprintf(((Integer) o[i]).intValue()));
							else
								if (o[i] instanceof Long) sb.append(cs.internalsprintf(((Long) o[i]).longValue()));
								else
									if (o[i] instanceof Float) sb.append(cs.internalsprintf(((Float) o[i]).floatValue()));
									else
										if (o[i] instanceof Double) sb.append(cs.internalsprintf(((Double) o[i]).doubleValue()));
										else
											if (o[i] instanceof Character) sb.append(cs.internalsprintf(((Character) o[i]).charValue()));
											else
												if (o[i] instanceof String) sb.append(cs.internalsprintf((String) o[i]));
												else sb.append(cs.internalsprintf(o[i]));
					if (!cs.isPositionalSpecification()) i++;
				}
		}
		return sb.toString();
	}

	/**
	 * Format nothing. Just use the control string.
	 * 
	 * @return the formatted String.
	 */
	public String sprintf() {
		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
		}
		return sb.toString();
	}

	/**
	 * Format an int.
	 * 
	 * @param x
	 *            The int to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(int x) throws IllegalArgumentException {
		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an long.
	 * 
	 * @param x
	 *            The long to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is f, e, E, g, G, s, or S.
	 */
	public String sprintf(long x) throws IllegalArgumentException {
		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a double.
	 * 
	 * @param x
	 *            The double to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is c, C, s, S, d, d, x, X, or o.
	 */
	public String sprintf(double x) throws IllegalArgumentException {
		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format a String.
	 * 
	 * @param x
	 *            The String to format.
	 * @return The formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is neither s nor S.
	 */
	public String sprintf(String x) throws IllegalArgumentException {

		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else sb.append(cs.internalsprintf(x));
		}
		return sb.toString();
	}

	/**
	 * Format an Object. Convert wrapper types to their primitive equivalents and call the appropriate internal formatting method. Convert Strings
	 * using an internal formatting method for Strings. Otherwise use the default formatter (use toString).
	 * 
	 * @param x
	 *            the Object to format.
	 * @return the formatted String.
	 * @exception IllegalArgumentException
	 *                if the conversion character is inappropriate for formatting an unwrapped value.
	 */
	public String sprintf(Object x) throws IllegalArgumentException {

		Iterator<ConversionSpecification> e = this.vFmt.iterator();
		ConversionSpecification cs = null;
		char c = 0;
		StringBuilder sb = new StringBuilder();
		while (e.hasNext()) {
			cs = e.next();
			c = cs.getConversionCharacter();
			if (c == '\0') sb.append(cs.getLiteral());
			else
				if (c == '%') sb.append('%');
				else {
					if (x instanceof Byte) sb.append(cs.internalsprintf(((Byte) x).byteValue()));
					else
						if (x instanceof Short) sb.append(cs.internalsprintf(((Short) x).shortValue()));
						else
							if (x instanceof Integer) sb.append(cs.internalsprintf(((Integer) x).intValue()));
							else
								if (x instanceof Long) sb.append(cs.internalsprintf(((Long) x).longValue()));
								else
									if (x instanceof Float) sb.append(cs.internalsprintf(((Float) x).floatValue()));
									else
										if (x instanceof Double) sb.append(cs.internalsprintf(((Double) x).doubleValue()));
										else
											if (x instanceof Character) sb.append(cs.internalsprintf(((Character) x).charValue()));
											else
												if (x instanceof String) sb.append(cs.internalsprintf((String) x));
												else sb.append(cs.internalsprintf(x));
				}
		}
		return sb.toString();
	}

	/**
	 * <p>
	 * ConversionSpecification allows the formatting of a single primitive or object embedded within a string. The formatting is controlled by a
	 * format string. Only one Java primitive or object can be formatted at a time.
	 * <p>
	 * A format string is a Java string that contains a control string. The control string starts at the first percent sign (%) in the string,
	 * provided that this percent sign
	 * <ol>
	 * <li>is not escaped protected by a matching % or is not an escape % character,
	 * <li>is not at the end of the format string, and
	 * <li>precedes a sequence of characters that parses as a valid control string.
	 * </ol>
	 * <p>
	 * A control string takes the form:
	 * 
	 * <pre>
	 * % ['-+ #0]* [0..9]* { . [0..9]* }+
	 *                { [hlL] }+ [idfgGoxXeEcs]
	 * </pre>
	 * <p>
	 * The behavior is like printf. One (hopefully the only) exception is that the minimum number of exponent digits is 3 instead of 2 for e and E
	 * formats when the optional L is used before the e, E, g, or G conversion character. The optional L does not imply conversion to a long long
	 * double.
	 */
	private class ConversionSpecification {
		/**
		 * Constructor. Used to prepare an instance to hold a literal, not a control string.
		 */
		ConversionSpecification() {}

		/**
		 * Constructor for a conversion specification. The argument must begin with a % and end with the conversion character for the conversion
		 * specification.
		 * 
		 * @param fmtArg
		 *            String specifying the conversion specification.
		 * @exception IllegalArgumentException
		 *                if the input string is null, zero length, or otherwise malformed.
		 */
		ConversionSpecification(String fmtArg) throws IllegalArgumentException {
			if (fmtArg == null) throw new NullPointerException();
			if (fmtArg.length() == 0) throw new IllegalArgumentException("Control strings must have positive" + " lengths.");
			if (fmtArg.charAt(0) == '%') {
				this.fmt = fmtArg;
				this.pos = 1;
				setArgPosition();
				setFlagCharacters();
				setFieldWidth();
				setPrecision();
				setOptionalHL();
				if (setConversionCharacter()) {
					if (this.pos == fmtArg.length()) {
						if (this.leadingZeros && this.leftJustify) this.leadingZeros = false;
						if (this.precisionSet && this.leadingZeros) {
							if (this.conversionCharacter == 'd' || this.conversionCharacter == 'i' || this.conversionCharacter == 'o'
									|| this.conversionCharacter == 'x') {
								this.leadingZeros = false;
							}
						}
					}
					else throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
				}
				else throw new IllegalArgumentException("Malformed conversion specification=" + fmtArg);
			}
			else throw new IllegalArgumentException("Control strings must begin with %.");
		}

		/**
		 * Set the String for this instance.
		 * 
		 * @param s
		 *            the String to store.
		 */
		void setLiteral(String s) {
			this.fmt = s;
		}

		/**
		 * Get the String for this instance. Translate any escape sequences.
		 * 
		 * @return s the stored String.
		 */
		String getLiteral() {

			return this.fmt;
		}

		/**
		 * Get the conversion character that tells what type of control character this instance has.
		 * 
		 * @return the conversion character.
		 */
		char getConversionCharacter() {
			return this.conversionCharacter;
		}

		/**
		 * Check whether the specifier has a variable field width that is going to be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * field width; otherwise <code>false</code>.
		 */
		boolean isVariableFieldWidth() {
			return this.variableFieldWidth;
		}

		/**
		 * Set the field width with an argument. A negative field width is taken as a - flag followed by a positive field width.
		 * 
		 * @param fw
		 *            the field width.
		 */
		void setFieldWidthWithArg(int fw) {
			if (fw < 0) this.leftJustify = true;
			this.fieldWidthSet = true;
			this.fieldWidth = Math.abs(fw);
		}

		/**
		 * Check whether the specifier has a variable precision that is going to be set by an argument.
		 * 
		 * @return <code>true</code> if the conversion uses an * precision; otherwise <code>false</code>.
		 */
		boolean isVariablePrecision() {
			return this.variablePrecision;
		}

		/**
		 * Set the precision with an argument. A negative precision will be changed to zero.
		 * 
		 * @param pr
		 *            the precision.
		 */
		void setPrecisionWithArg(int pr) {
			this.precisionSet = true;
			this.precision = Math.max(pr, 0);
		}

		/**
		 * Format an int argument using this conversion specification.
		 * 
		 * @param s
		 *            the int to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(int s) throws IllegalArgumentException {
			String s2 = "";
			switch (this.conversionCharacter) {
				case 'd':
				case 'i':
					if (this.optionalh) s2 = printDFormat((short) s);
					else
						if (this.optionall) s2 = printDFormat((long) s);
						else s2 = printDFormat(s);
					break;
				case 'x':
				case 'X':
					if (this.optionalh) s2 = printXFormat((short) s);
					else
						if (this.optionall) s2 = printXFormat((long) s);
						else s2 = printXFormat(s);
					break;
				case 'o':
					if (this.optionalh) s2 = printOFormat((short) s);
					else
						if (this.optionall) s2 = printOFormat((long) s);
						else s2 = printOFormat(s);
					break;
				case 'c':
				case 'C':
					s2 = printCFormat((char) s);
					break;
				default:
					throw new IllegalArgumentException("Cannot format a int with a format using a " + this.conversionCharacter
							+ " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a long argument using this conversion specification.
		 * 
		 * @param s
		 *            the long to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is f, e, E, g, or G.
		 */
		String internalsprintf(long s) throws IllegalArgumentException {
			String s2 = "";
			switch (this.conversionCharacter) {
				case 'd':
				case 'i':
					if (this.optionalh) s2 = printDFormat((short) s);
					else
						if (this.optionall) s2 = printDFormat(s);
						else s2 = printDFormat((int) s);
					break;
				case 'x':
				case 'X':
					if (this.optionalh) s2 = printXFormat((short) s);
					else
						if (this.optionall) s2 = printXFormat(s);
						else s2 = printXFormat((int) s);
					break;
				case 'o':
					if (this.optionalh) s2 = printOFormat((short) s);
					else
						if (this.optionall) s2 = printOFormat(s);
						else s2 = printOFormat((int) s);
					break;
				case 'c':
				case 'C':
					s2 = printCFormat((char) s);
					break;
				default:
					throw new IllegalArgumentException("Cannot format a long with a format using a " + this.conversionCharacter
							+ " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a double argument using this conversion specification.
		 * 
		 * @param s
		 *            the double to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is c, C, s, S, i, d, x, X, or o.
		 */
		String internalsprintf(double s) throws IllegalArgumentException {
			String s2 = "";
			switch (this.conversionCharacter) {
				case 'f':
					s2 = printFFormat(s);
					break;
				case 'E':
				case 'e':
					s2 = printEFormat(s);
					break;
				case 'G':
				case 'g':
					s2 = printGFormat(s);
					break;
				default:
					throw new IllegalArgumentException("Cannot " + "format a double with a format using a " + this.conversionCharacter
							+ " conversion character.");
			}
			return s2;
		}

		/**
		 * Format a String argument using this conversion specification.
		 * 
		 * @param s
		 *            the String to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is neither s nor S.
		 */
		String internalsprintf(String s) throws IllegalArgumentException {
			String s2 = "";
			if (this.conversionCharacter == 's' || this.conversionCharacter == 'S') s2 = printSFormat(s);
			else throw new IllegalArgumentException("Cannot " + "format a String with a format using a " + this.conversionCharacter
					+ " conversion character.");
			return s2;
		}

		/**
		 * Format an Object argument using this conversion specification.
		 * 
		 * @param s
		 *            the Object to format.
		 * @return the formatted String.
		 * @exception IllegalArgumentException
		 *                if the conversion character is neither s nor S.
		 */
		String internalsprintf(Object s) {
			String s2 = "";
			if (this.conversionCharacter == 's' || this.conversionCharacter == 'S') s2 = printSFormat(s.toString());
			else throw new IllegalArgumentException("Cannot format a String with a format using" + " a " + this.conversionCharacter
					+ " conversion character.");
			return s2;
		}

		/**
		 * For f format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the number of digits to appear after the radix character. Padding is with trailing 0s.
		 */
		private char[] fFormatDigits(double x) {
			// int defaultDigits=6;
			String sx;// sxOut;
			int i, j, k;
			int n1In, n2In;
			int expon = 0;
			boolean minusSign = false;
			if (x > 0.0) sx = Double.toString(x);
			else
				if (x < 0.0) {
					sx = Double.toString(-x);
					minusSign = true;
				}
				else {
					sx = Double.toString(x);
					if (sx.charAt(0) == '-') {
						minusSign = true;
						sx = sx.substring(1);
					}
				}
			int ePos = sx.indexOf('E');
			int rPos = sx.indexOf('.');
			if (rPos != -1) n1In = rPos;
			else
				if (ePos != -1) n1In = ePos;
				else n1In = sx.length();
			if (rPos != -1) {
				if (ePos != -1) n2In = ePos - rPos - 1;
				else n2In = sx.length() - rPos - 1;
			}
			else n2In = 0;
			if (ePos != -1) {
				int ie = ePos + 1;
				expon = 0;
				if (sx.charAt(ie) == '-') {
					for (++ie; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0') break;
					if (ie < sx.length()) expon = -Integer.parseInt(sx.substring(ie));
				}
				else {
					if (sx.charAt(ie) == '+') ++ie;
					for (; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0') break;
					if (ie < sx.length()) expon = Integer.parseInt(sx.substring(ie));
				}
			}
			int p;
			if (this.precisionSet) p = this.precision;
			else p = defaultDigits - 1;
			char[] ca1 = sx.toCharArray();
			char[] ca2 = new char[n1In + n2In];
			char[] ca3, ca4, ca5;
			for (j = 0; j < n1In; j++)
				ca2[j] = ca1[j];
			i = j + 1;
			for (k = 0; k < n2In; j++, i++, k++)
				ca2[j] = ca1[i];
			if (n1In + expon <= 0) {
				ca3 = new char[-expon + n2In];
				for (j = 0, k = 0; k < (-n1In - expon); k++, j++)
					ca3[j] = '0';
				for (i = 0; i < (n1In + n2In); i++, j++)
					ca3[j] = ca2[i];
			}
			else ca3 = ca2;
			boolean carry = false;
			if (p < -expon + n2In) {
				if (expon < 0) i = p;
				else i = p + n1In;
				carry = checkForCarry(ca3, i);
				if (carry) carry = startSymbolicCarry(ca3, i - 1, 0);
			}
			if (n1In + expon <= 0) {
				ca4 = new char[2 + p];
				if (!carry) ca4[0] = '0';
				else ca4[0] = '1';
				if (this.alternateForm || !this.precisionSet || this.precision != 0) {
					ca4[1] = '.';
					for (i = 0, j = 2; i < Math.min(p, ca3.length); i++, j++)
						ca4[j] = ca3[i];
					for (; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			else {
				if (!carry) {
					if (this.alternateForm || !this.precisionSet || this.precision != 0) ca4 = new char[n1In + expon + p + 1];
					else ca4 = new char[n1In + expon];
					j = 0;
				}
				else {
					if (this.alternateForm || !this.precisionSet || this.precision != 0) ca4 = new char[n1In + expon + p + 2];
					else ca4 = new char[n1In + expon + 1];
					ca4[0] = '1';
					j = 1;
				}
				for (i = 0; i < Math.min(n1In + expon, ca3.length); i++, j++)
					ca4[j] = ca3[i];
				for (; i < n1In + expon; i++, j++)
					ca4[j] = '0';
				if (this.alternateForm || !this.precisionSet || this.precision != 0) {
					ca4[j] = '.';
					j++;
					for (k = 0; i < ca3.length && k < p; i++, j++, k++)
						ca4[j] = ca3[i];
					for (; j < ca4.length; j++)
						ca4[j] = '0';
				}
			}
			int nZeros = 0;
			if (!this.leftJustify && this.leadingZeros) {
				int xThousands = 0;
				if (this.thousands) {
					int xlead = 0;
					if (ca4[0] == '+' || ca4[0] == '-' || ca4[0] == ' ') xlead = 1;
					int xdp = xlead;
					for (; xdp < ca4.length; xdp++)
						if (ca4[xdp] == '.') break;
					xThousands = (xdp - xlead) / 3;
				}
				if (this.fieldWidthSet) nZeros = this.fieldWidth - ca4.length;
				if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) nZeros--;
				nZeros -= xThousands;
				if (nZeros < 0) nZeros = 0;
			}
			j = 0;
			if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) {
				ca5 = new char[ca4.length + nZeros + 1];
				j++;
			}
			else ca5 = new char[ca4.length + nZeros];
			if (!minusSign) {
				if (this.leadingSign) ca5[0] = '+';
				if (this.leadingSpace) ca5[0] = ' ';
			}
			else ca5[0] = '-';
			for (i = 0; i < nZeros; i++, j++)
				ca5[j] = '0';
			for (i = 0; i < ca4.length; i++, j++)
				ca5[j] = ca4[i];

			int lead = 0;
			if (ca5[0] == '+' || ca5[0] == '-' || ca5[0] == ' ') lead = 1;
			int dp = lead;
			for (; dp < ca5.length; dp++)
				if (ca5[dp] == '.') break;
			int nThousands = (dp - lead) / 3;
			// Localize the decimal point.
			if (dp < ca5.length) ca5[dp] = PrintfFormat.this.dfs.getDecimalSeparator();
			char[] ca6 = ca5;
			if (this.thousands && nThousands > 0) {
				ca6 = new char[ca5.length + nThousands + lead];
				ca6[0] = ca5[0];
				for (i = lead, k = lead; i < dp; i++) {
					if (i > 0 && (dp - i) % 3 == 0) {
						// ca6[k]=',';
						ca6[k] = PrintfFormat.this.dfs.getGroupingSeparator();
						ca6[k + 1] = ca5[i];
						k += 2;
					}
					else {
						ca6[k] = ca5[i];
						k++;
					}
				}
				for (; i < ca5.length; i++, k++) {
					ca6[k] = ca5[i];
				}
			}
			return ca6;
		}

		/**
		 * An intermediate routine on the way to creating an f format String. The method decides whether the input double value is an infinity,
		 * not-a-number, or a finite double and formats each type of input appropriately.
		 * 
		 * @param x
		 *            the double value to be formatted.
		 * @return the converted double value.
		 */
		private String fFormatString(double x) {
			// boolean noDigits=false;
			char[] ca6, ca7;
			if (Double.isInfinite(x)) {
				if (x == Double.POSITIVE_INFINITY) {
					if (this.leadingSign) ca6 = "+Inf".toCharArray();
					else
						if (this.leadingSpace) ca6 = " Inf".toCharArray();
						else ca6 = "Inf".toCharArray();
				}
				else ca6 = "-Inf".toCharArray();
				// noDigits = true;
			}
			else
				if (Double.isNaN(x)) {
					if (this.leadingSign) ca6 = "+NaN".toCharArray();
					else
						if (this.leadingSpace) ca6 = " NaN".toCharArray();
						else ca6 = "NaN".toCharArray();
					// noDigits = true;
				}
				else ca6 = fFormatDigits(x);
			ca7 = applyFloatPadding(ca6, false);
			return new String(ca7);
		}

		/**
		 * For e format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear after the radix character. Padding is with trailing 0s.
		 * 
		 * The behavior is like printf. One (hopefully the only) exception is that the minimum number of exponent digits is 3 instead of 2 for e and E
		 * formats when the optional L is used before the e, E, g, or G conversion character. The optional L does not imply conversion to a long long
		 * double.
		 */
		private char[] eFormatDigits(double x, char eChar) {
			char[] ca1, ca2, ca3;
			// int defaultDigits=6;
			String sx;// sxOut;
			int i, j, k, p;
			// int n1In,n2In;
			int expon = 0;
			int ePos, rPos, eSize;
			boolean minusSign = false;
			if (x > 0.0) sx = Double.toString(x);
			else
				if (x < 0.0) {
					sx = Double.toString(-x);
					minusSign = true;
				}
				else {
					sx = Double.toString(x);
					if (sx.charAt(0) == '-') {
						minusSign = true;
						sx = sx.substring(1);
					}
				}
			ePos = sx.indexOf('E');
			if (ePos == -1) ePos = sx.indexOf('e');
			rPos = sx.indexOf('.');
			// if (rPos!=-1)
			// n1In=rPos;
			// else if (ePos!=-1)
			// n1In=ePos;
			// else
			// n1In=sx.length();
			// if (rPos!=-1) {
			// if (ePos!=-1)
			// n2In = ePos-rPos-1;
			// else
			// n2In = sx.length()-rPos-1;
			// }
			// else
			// n2In = 0;

			if (ePos != -1) {
				int ie = ePos + 1;
				expon = 0;
				if (sx.charAt(ie) == '-') {
					for (++ie; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0') break;
					if (ie < sx.length()) expon = -Integer.parseInt(sx.substring(ie));
				}
				else {
					if (sx.charAt(ie) == '+') ++ie;
					for (; ie < sx.length(); ie++)
						if (sx.charAt(ie) != '0') break;
					if (ie < sx.length()) expon = Integer.parseInt(sx.substring(ie));
				}
			}
			if (rPos != -1) expon += rPos - 1;
			if (this.precisionSet) p = this.precision;
			else p = defaultDigits - 1;
			if (rPos != -1 && ePos != -1) ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1, ePos)).toCharArray();
			else
				if (rPos != -1) ca1 = (sx.substring(0, rPos) + sx.substring(rPos + 1)).toCharArray();
				else
					if (ePos != -1) ca1 = sx.substring(0, ePos).toCharArray();
					else ca1 = sx.toCharArray();
			boolean carry = false;
			int i0 = 0;
			if (ca1[0] != '0') i0 = 0;
			else for (i0 = 0; i0 < ca1.length; i0++)
				if (ca1[i0] != '0') break;
			if (i0 + p < ca1.length - 1) {
				carry = checkForCarry(ca1, i0 + p + 1);
				if (carry) carry = startSymbolicCarry(ca1, i0 + p, i0);
				if (carry) {
					ca2 = new char[i0 + p + 1];
					ca2[i0] = '1';
					for (j = 0; j < i0; j++)
						ca2[j] = '0';
					for (i = i0, j = i0 + 1; j < p + 1; i++, j++)
						ca2[j] = ca1[i];
					expon++;
					ca1 = ca2;
				}
			}
			if (Math.abs(expon) < 100 && !this.optionalL) eSize = 4;
			else eSize = 5;
			if (this.alternateForm || !this.precisionSet || this.precision != 0) ca2 = new char[2 + p + eSize];
			else ca2 = new char[1 + eSize];
			if (ca1[0] != '0') {
				ca2[0] = ca1[0];
				j = 1;
			}
			else {
				for (j = 1; j < (ePos == -1 ? ca1.length : ePos); j++)
					if (ca1[j] != '0') break;
				if ((ePos != -1 && j < ePos) || (ePos == -1 && j < ca1.length)) {
					ca2[0] = ca1[j];
					expon -= j;
					j++;
				}
				else {
					ca2[0] = '0';
					j = 2;
				}
			}
			if (this.alternateForm || !this.precisionSet || this.precision != 0) {
				ca2[1] = '.';
				i = 2;
			}
			else i = 1;
			for (k = 0; k < p && j < ca1.length; j++, i++, k++)
				ca2[i] = ca1[j];
			for (; i < ca2.length - eSize; i++)
				ca2[i] = '0';
			ca2[i++] = eChar;
			if (expon < 0) ca2[i++] = '-';
			else ca2[i++] = '+';
			expon = Math.abs(expon);
			if (expon >= 100) {
				switch (expon / 100) {
					case 1:
						ca2[i] = '1';
						break;
					case 2:
						ca2[i] = '2';
						break;
					case 3:
						ca2[i] = '3';
						break;
					case 4:
						ca2[i] = '4';
						break;
					case 5:
						ca2[i] = '5';
						break;
					case 6:
						ca2[i] = '6';
						break;
					case 7:
						ca2[i] = '7';
						break;
					case 8:
						ca2[i] = '8';
						break;
					case 9:
						ca2[i] = '9';
						break;
				}
				i++;
			}
			switch ((expon % 100) / 10) {
				case 0:
					ca2[i] = '0';
					break;
				case 1:
					ca2[i] = '1';
					break;
				case 2:
					ca2[i] = '2';
					break;
				case 3:
					ca2[i] = '3';
					break;
				case 4:
					ca2[i] = '4';
					break;
				case 5:
					ca2[i] = '5';
					break;
				case 6:
					ca2[i] = '6';
					break;
				case 7:
					ca2[i] = '7';
					break;
				case 8:
					ca2[i] = '8';
					break;
				case 9:
					ca2[i] = '9';
					break;
			}
			i++;
			switch (expon % 10) {
				case 0:
					ca2[i] = '0';
					break;
				case 1:
					ca2[i] = '1';
					break;
				case 2:
					ca2[i] = '2';
					break;
				case 3:
					ca2[i] = '3';
					break;
				case 4:
					ca2[i] = '4';
					break;
				case 5:
					ca2[i] = '5';
					break;
				case 6:
					ca2[i] = '6';
					break;
				case 7:
					ca2[i] = '7';
					break;
				case 8:
					ca2[i] = '8';
					break;
				case 9:
					ca2[i] = '9';
					break;
			}
			int nZeros = 0;
			if (!this.leftJustify && this.leadingZeros) {
				int xThousands = 0;
				if (this.thousands) {
					int xlead = 0;
					if (ca2[0] == '+' || ca2[0] == '-' || ca2[0] == ' ') xlead = 1;
					int xdp = xlead;
					for (; xdp < ca2.length; xdp++)
						if (ca2[xdp] == '.') break;
					xThousands = (xdp - xlead) / 3;
				}
				if (this.fieldWidthSet) nZeros = this.fieldWidth - ca2.length;
				if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) nZeros--;
				nZeros -= xThousands;
				if (nZeros < 0) nZeros = 0;
			}
			j = 0;
			if ((!minusSign && (this.leadingSign || this.leadingSpace)) || minusSign) {
				ca3 = new char[ca2.length + nZeros + 1];
				j++;
			}
			else ca3 = new char[ca2.length + nZeros];
			if (!minusSign) {
				if (this.leadingSign) ca3[0] = '+';
				if (this.leadingSpace) ca3[0] = ' ';
			}
			else ca3[0] = '-';
			for (k = 0; k < nZeros; j++, k++)
				ca3[j] = '0';
			for (i = 0; i < ca2.length && j < ca3.length; i++, j++)
				ca3[j] = ca2[i];

			int lead = 0;
			if (ca3[0] == '+' || ca3[0] == '-' || ca3[0] == ' ') lead = 1;
			int dp = lead;
			for (; dp < ca3.length; dp++)
				if (ca3[dp] == '.') break;
			int nThousands = dp / 3;
			// Localize the decimal point.
			if (dp < ca3.length) ca3[dp] = PrintfFormat.this.dfs.getDecimalSeparator();
			char[] ca4 = ca3;
			if (this.thousands && nThousands > 0) {
				ca4 = new char[ca3.length + nThousands + lead];
				ca4[0] = ca3[0];
				for (i = lead, k = lead; i < dp; i++) {
					if (i > 0 && (dp - i) % 3 == 0) {
						// ca4[k]=',';
						ca4[k] = PrintfFormat.this.dfs.getGroupingSeparator();
						ca4[k + 1] = ca3[i];
						k += 2;
					}
					else {
						ca4[k] = ca3[i];
						k++;
					}
				}
				for (; i < ca3.length; i++, k++)
					ca4[k] = ca3[i];
			}
			return ca4;
		}

		/**
		 * Check to see if the digits that are going to be truncated because of the precision should force a round in the preceding digits.
		 * 
		 * @param ca1
		 *            the array of digits
		 * @param icarry
		 *            the index of the first digit that is to be truncated from the print
		 * @return <code>true</code> if the truncation forces a round that will change the print
		 */
		private boolean checkForCarry(char[] ca1, int icarry) {
			boolean carry = false;
			if (icarry < ca1.length) {
				if (ca1[icarry] == '6' || ca1[icarry] == '7' || ca1[icarry] == '8' || ca1[icarry] == '9') carry = true;
				else
					if (ca1[icarry] == '5') {
						int ii = icarry + 1;
						for (; ii < ca1.length; ii++)
							if (ca1[ii] != '0') break;
						carry = ii < ca1.length;
						if (!carry && icarry > 0) {
							carry = (ca1[icarry - 1] == '1' || ca1[icarry - 1] == '3' || ca1[icarry - 1] == '5' || ca1[icarry - 1] == '7' || ca1[icarry - 1] == '9');
						}
					}
			}
			return carry;
		}

		/**
		 * Start the symbolic carry process. The process is not quite finished because the symbolic carry may change the length of the string and
		 * change the exponent (in e format).
		 * 
		 * @param cLast
		 *            index of the last digit changed by the round
		 * @param cFirst
		 *            index of the first digit allowed to be changed by this phase of the round
		 * @return <code>true</code> if the carry forces a round that will change the print still more
		 */
		private boolean startSymbolicCarry(char[] ca, int cLast, int cFirst) {
			boolean carry = true;
			for (int i = cLast; carry && i >= cFirst; i--) {
				carry = false;
				switch (ca[i]) {
					case '0':
						ca[i] = '1';
						break;
					case '1':
						ca[i] = '2';
						break;
					case '2':
						ca[i] = '3';
						break;
					case '3':
						ca[i] = '4';
						break;
					case '4':
						ca[i] = '5';
						break;
					case '5':
						ca[i] = '6';
						break;
					case '6':
						ca[i] = '7';
						break;
					case '7':
						ca[i] = '8';
						break;
					case '8':
						ca[i] = '9';
						break;
					case '9':
						ca[i] = '0';
						carry = true;
						break;
				}
			}
			return carry;
		}

		/**
		 * An intermediate routine on the way to creating an e format String. The method decides whether the input double value is an infinity,
		 * not-a-number, or a finite double and formats each type of input appropriately.
		 * 
		 * @param x
		 *            the double value to be formatted.
		 * @param eChar
		 *            an 'e' or 'E' to use in the converted double value.
		 * @return the converted double value.
		 */
		private String eFormatString(double x, char eChar) {
			// boolean noDigits=false;
			char[] ca4, ca5;
			if (Double.isInfinite(x)) {
				if (x == Double.POSITIVE_INFINITY) {
					if (this.leadingSign) ca4 = "+Inf".toCharArray();
					else
						if (this.leadingSpace) ca4 = " Inf".toCharArray();
						else ca4 = "Inf".toCharArray();
				}
				else ca4 = "-Inf".toCharArray();
				// noDigits = true;
			}
			else
				if (Double.isNaN(x)) {
					if (this.leadingSign) ca4 = "+NaN".toCharArray();
					else
						if (this.leadingSpace) ca4 = " NaN".toCharArray();
						else ca4 = "NaN".toCharArray();
					// noDigits = true;
				}
				else ca4 = eFormatDigits(x, eChar);
			ca5 = applyFloatPadding(ca4, false);
			return new String(ca5);
		}

		/**
		 * Apply zero or blank, left or right padding.
		 * 
		 * @param ca4
		 *            array of characters before padding is finished
		 * @param noDigits
		 *            NaN or signed Inf
		 * @return a padded array of characters
		 */
		private char[] applyFloatPadding(char[] ca4, boolean noDigits) {
			char[] ca5 = ca4;
			if (this.fieldWidthSet) {
				int i, j, nBlanks;
				if (this.leftJustify) {
					nBlanks = this.fieldWidth - ca4.length;
					if (nBlanks > 0) {
						ca5 = new char[ca4.length + nBlanks];
						for (i = 0; i < ca4.length; i++)
							ca5[i] = ca4[i];
						for (j = 0; j < nBlanks; j++, i++)
							ca5[i] = ' ';
					}
				}
				else
					if (!this.leadingZeros || noDigits) {
						nBlanks = this.fieldWidth - ca4.length;
						if (nBlanks > 0) {
							ca5 = new char[ca4.length + nBlanks];
							for (i = 0; i < nBlanks; i++)
								ca5[i] = ' ';
							for (j = 0; j < ca4.length; i++, j++)
								ca5[i] = ca4[j];
						}
					}
					else
						if (this.leadingZeros) {
							nBlanks = this.fieldWidth - ca4.length;
							if (nBlanks > 0) {
								ca5 = new char[ca4.length + nBlanks];
								i = 0;
								j = 0;
								if (ca4[0] == '-') {
									ca5[0] = '-';
									i++;
									j++;
								}
								for (int k = 0; k < nBlanks; i++, k++)
									ca5[i] = '0';
								for (; j < ca4.length; i++, j++)
									ca5[i] = ca4[j];
							}
						}
			}
			return ca5;
		}

		/**
		 * Format method for the f conversion character.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printFFormat(double x) {
			return fFormatString(x);
		}

		/**
		 * Format method for the e or E conversion character.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printEFormat(double x) {
			if (this.conversionCharacter == 'e') return eFormatString(x, 'e');
			else return eFormatString(x, 'E');
		}

		/**
		 * Format method for the g conversion character.
		 * 
		 * For g format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear after the radix character. Padding is with trailing 0s.
		 * 
		 * @param x
		 *            the double to format.
		 * @return the formatted String.
		 */
		private String printGFormat(double x) {
			String sx, sy, sz, ret;
			int savePrecision = this.precision;
			int i;
			char[] ca4, ca5;
			// boolean noDigits=false;
			if (Double.isInfinite(x)) {
				if (x == Double.POSITIVE_INFINITY) {
					if (this.leadingSign) ca4 = "+Inf".toCharArray();
					else
						if (this.leadingSpace) ca4 = " Inf".toCharArray();
						else ca4 = "Inf".toCharArray();
				}
				else ca4 = "-Inf".toCharArray();
				// noDigits = true;
			}
			else
				if (Double.isNaN(x)) {
					if (this.leadingSign) ca4 = "+NaN".toCharArray();
					else
						if (this.leadingSpace) ca4 = " NaN".toCharArray();
						else ca4 = "NaN".toCharArray();
					// noDigits = true;
				}
				else {
					if (!this.precisionSet) this.precision = defaultDigits;
					if (this.precision == 0) this.precision = 1;
					int ePos = -1;
					if (this.conversionCharacter == 'g') {
						sx = eFormatString(x, 'e').trim();
						ePos = sx.indexOf('e');
					}
					else {
						sx = eFormatString(x, 'E').trim();
						ePos = sx.indexOf('E');
					}
					i = ePos + 1;
					int expon = 0;
					if (sx.charAt(i) == '-') {
						for (++i; i < sx.length(); i++)
							if (sx.charAt(i) != '0') break;
						if (i < sx.length()) expon = -Integer.parseInt(sx.substring(i));
					}
					else {
						if (sx.charAt(i) == '+') ++i;
						for (; i < sx.length(); i++)
							if (sx.charAt(i) != '0') break;
						if (i < sx.length()) expon = Integer.parseInt(sx.substring(i));
					}
					// Trim trailing zeros.
					// If the radix character is not followed by
					// a digit, trim it, too.
					if (!this.alternateForm) {
						if (expon >= -4 && expon < this.precision) sy = fFormatString(x).trim();
						else sy = sx.substring(0, ePos);
						i = sy.length() - 1;
						for (; i >= 0; i--)
							if (sy.charAt(i) != '0') break;
						if (i >= 0 && sy.charAt(i) == '.') i--;
						if (i == -1) sz = "0";
						else
							if (!Character.isDigit(sy.charAt(i))) sz = sy.substring(0, i + 1) + '0';
							else sz = sy.substring(0, i + 1);
						if (expon >= -4 && expon < this.precision) ret = sz;
						else ret = sz + sx.substring(ePos);
					}
					else {
						if (expon >= -4 && expon < this.precision) ret = fFormatString(x).trim();
						else ret = sx;
					}
					// leading space was trimmed off during
					// construction
					if (this.leadingSpace) if (x >= 0) ret = ' ' + ret;
					ca4 = ret.toCharArray();
				}
			// Pad with blanks or zeros.
			ca5 = applyFloatPadding(ca4, false);
			this.precision = savePrecision;
			return new String(ca5);
		}

		/**
		 * Format method for the d conversion specifer and short argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printDFormat(short x) {
			return printDFormat(Short.toString(x));
		}

		/**
		 * Format method for the d conversion character and long argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printDFormat(long x) {
			return printDFormat(Long.toString(x));
		}

		/**
		 * Format method for the d conversion character and int argument.
		 * 
		 * For d format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. A '+' character means that the conversion will always begin with a sign (+ or -). The blank flag character means that a
		 * non-negative input will be preceded with a blank. If both a '+' and a ' ' are specified, the blank flag is ignored. The '0' flag character
		 * implies that padding to the field width will be done with zeros instead of blanks.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printDFormat(int x) {
			return printDFormat(Integer.toString(x));
		}

		/**
		 * Utility method for formatting using the d conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printDFormat(String sx) {
			int nLeadingZeros = 0;
			int nBlanks = 0, n = 0;
			int i = 0, jFirst = 0;
			boolean neg = sx.charAt(0) == '-';
			if (sx.equals("0") && this.precisionSet && this.precision == 0) sx = "";
			if (!neg) {
				if (this.precisionSet && sx.length() < this.precision) nLeadingZeros = this.precision - sx.length();
			}
			else {
				if (this.precisionSet && (sx.length() - 1) < this.precision) nLeadingZeros = this.precision - sx.length() + 1;
			}
			if (nLeadingZeros < 0) nLeadingZeros = 0;
			if (this.fieldWidthSet) {
				nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
				if (!neg && (this.leadingSign || this.leadingSpace)) nBlanks--;
			}
			if (nBlanks < 0) nBlanks = 0;
			if (this.leadingSign) n++;
			else
				if (this.leadingSpace) n++;
			n += nBlanks;
			n += nLeadingZeros;
			n += sx.length();
			char[] ca = new char[n];
			if (this.leftJustify) {
				if (neg) ca[i++] = '-';
				else
					if (this.leadingSign) ca[i++] = '+';
					else
						if (this.leadingSpace) ca[i++] = ' ';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for (int j = 0; j < nLeadingZeros; i++, j++)
					ca[i] = '0';
				for (int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; i++, j++)
					ca[i] = ' ';
			}
			else {
				if (!this.leadingZeros) {
					for (i = 0; i < nBlanks; i++)
						ca[i] = ' ';
					if (neg) ca[i++] = '-';
					else
						if (this.leadingSign) ca[i++] = '+';
						else
							if (this.leadingSpace) ca[i++] = ' ';
				}
				else {
					if (neg) ca[i++] = '-';
					else
						if (this.leadingSign) ca[i++] = '+';
						else
							if (this.leadingSpace) ca[i++] = ' ';
					for (int j = 0; j < nBlanks; j++, i++)
						ca[i] = '0';
				}
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				jFirst = neg ? 1 : 0;
				for (int j = jFirst; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the x conversion character and short argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printXFormat(short x) {
			String sx = null;
			if (x == Short.MIN_VALUE) sx = "8000";
			else
				if (x < 0) {
					String t;
					if (x == Short.MIN_VALUE) t = "0";
					else {
						t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 16);
						if (t.charAt(0) == 'F' || t.charAt(0) == 'f') t = t.substring(16, 32);
					}
					switch (t.length()) {
						case 1:
							sx = "800" + t;
							break;
						case 2:
							sx = "80" + t;
							break;
						case 3:
							sx = '8' + t;
							break;
						case 4:
							switch (t.charAt(0)) {
								case '1':
									sx = '9' + t.substring(1, 4);
									break;
								case '2':
									sx = 'a' + t.substring(1, 4);
									break;
								case '3':
									sx = 'b' + t.substring(1, 4);
									break;
								case '4':
									sx = 'c' + t.substring(1, 4);
									break;
								case '5':
									sx = 'd' + t.substring(1, 4);
									break;
								case '6':
									sx = 'e' + t.substring(1, 4);
									break;
								case '7':
									sx = 'f' + t.substring(1, 4);
									break;
							}
							break;
					}
				}
				else sx = Integer.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and long argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printXFormat(long x) {
			String sx = null;
			if (x == Long.MIN_VALUE) sx = "8000000000000000";
			else
				if (x < 0) {
					String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 16);
					switch (t.length()) {
						case 1:
							sx = "800000000000000" + t;
							break;
						case 2:
							sx = "80000000000000" + t;
							break;
						case 3:
							sx = "8000000000000" + t;
							break;
						case 4:
							sx = "800000000000" + t;
							break;
						case 5:
							sx = "80000000000" + t;
							break;
						case 6:
							sx = "8000000000" + t;
							break;
						case 7:
							sx = "800000000" + t;
							break;
						case 8:
							sx = "80000000" + t;
							break;
						case 9:
							sx = "8000000" + t;
							break;
						case 10:
							sx = "800000" + t;
							break;
						case 11:
							sx = "80000" + t;
							break;
						case 12:
							sx = "8000" + t;
							break;
						case 13:
							sx = "800" + t;
							break;
						case 14:
							sx = "80" + t;
							break;
						case 15:
							sx = '8' + t;
							break;
						case 16:
							switch (t.charAt(0)) {
								case '1':
									sx = '9' + t.substring(1, 16);
									break;
								case '2':
									sx = 'a' + t.substring(1, 16);
									break;
								case '3':
									sx = 'b' + t.substring(1, 16);
									break;
								case '4':
									sx = 'c' + t.substring(1, 16);
									break;
								case '5':
									sx = 'd' + t.substring(1, 16);
									break;
								case '6':
									sx = 'e' + t.substring(1, 16);
									break;
								case '7':
									sx = 'f' + t.substring(1, 16);
									break;
							}
							break;
					}
				}
				else sx = Long.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Format method for the x conversion character and int argument.
		 * 
		 * For x format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means to lead with '0x'.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printXFormat(int x) {
			String sx = null;
			if (x == Integer.MIN_VALUE) sx = "80000000";
			else
				if (x < 0) {
					String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 16);
					switch (t.length()) {
						case 1:
							sx = "8000000" + t;
							break;
						case 2:
							sx = "800000" + t;
							break;
						case 3:
							sx = "80000" + t;
							break;
						case 4:
							sx = "8000" + t;
							break;
						case 5:
							sx = "800" + t;
							break;
						case 6:
							sx = "80" + t;
							break;
						case 7:
							sx = '8' + t;
							break;
						case 8:
							switch (t.charAt(0)) {
								case '1':
									sx = '9' + t.substring(1, 8);
									break;
								case '2':
									sx = 'a' + t.substring(1, 8);
									break;
								case '3':
									sx = 'b' + t.substring(1, 8);
									break;
								case '4':
									sx = 'c' + t.substring(1, 8);
									break;
								case '5':
									sx = 'd' + t.substring(1, 8);
									break;
								case '6':
									sx = 'e' + t.substring(1, 8);
									break;
								case '7':
									sx = 'f' + t.substring(1, 8);
									break;
							}
							break;
					}
				}
				else sx = Integer.toString(x, 16);
			return printXFormat(sx);
		}

		/**
		 * Utility method for formatting using the x conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printXFormat(String sx) {
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if (sx.equals("0") && this.precisionSet && this.precision == 0) sx = "";
			if (this.precisionSet) nLeadingZeros = this.precision - sx.length();
			if (nLeadingZeros < 0) nLeadingZeros = 0;
			if (this.fieldWidthSet) {
				nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
				if (this.alternateForm) nBlanks = nBlanks - 2;
			}
			if (nBlanks < 0) nBlanks = 0;
			int n = 0;
			if (this.alternateForm) n += 2;
			n += nLeadingZeros;
			n += sx.length();
			n += nBlanks;
			char[] ca = new char[n];
			int i = 0;
			if (this.leftJustify) {
				if (this.alternateForm) {
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else {
				if (!this.leadingZeros) for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
				if (this.alternateForm) {
					ca[i++] = '0';
					ca[i++] = 'x';
				}
				if (this.leadingZeros) for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = '0';
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			String caReturn = new String(ca);
			if (this.conversionCharacter == 'X') caReturn = caReturn.toUpperCase();
			return caReturn;
		}

		/**
		 * Format method for the o conversion character and short argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the short to format.
		 * @return the formatted String.
		 */
		private String printOFormat(short x) {
			String sx = null;
			if (x == Short.MIN_VALUE) sx = "100000";
			else
				if (x < 0) {
					String t = Integer.toString((~(-x - 1)) ^ Short.MIN_VALUE, 8);
					switch (t.length()) {
						case 1:
							sx = "10000" + t;
							break;
						case 2:
							sx = "1000" + t;
							break;
						case 3:
							sx = "100" + t;
							break;
						case 4:
							sx = "10" + t;
							break;
						case 5:
							sx = '1' + t;
							break;
					}
				}
				else sx = Integer.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and long argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the long to format.
		 * @return the formatted String.
		 */
		private String printOFormat(long x) {
			String sx = null;
			if (x == Long.MIN_VALUE) sx = "1000000000000000000000";
			else
				if (x < 0) {
					String t = Long.toString((~(-x - 1)) ^ Long.MIN_VALUE, 8);
					switch (t.length()) {
						case 1:
							sx = "100000000000000000000" + t;
							break;
						case 2:
							sx = "10000000000000000000" + t;
							break;
						case 3:
							sx = "1000000000000000000" + t;
							break;
						case 4:
							sx = "100000000000000000" + t;
							break;
						case 5:
							sx = "10000000000000000" + t;
							break;
						case 6:
							sx = "1000000000000000" + t;
							break;
						case 7:
							sx = "100000000000000" + t;
							break;
						case 8:
							sx = "10000000000000" + t;
							break;
						case 9:
							sx = "1000000000000" + t;
							break;
						case 10:
							sx = "100000000000" + t;
							break;
						case 11:
							sx = "10000000000" + t;
							break;
						case 12:
							sx = "1000000000" + t;
							break;
						case 13:
							sx = "100000000" + t;
							break;
						case 14:
							sx = "10000000" + t;
							break;
						case 15:
							sx = "1000000" + t;
							break;
						case 16:
							sx = "100000" + t;
							break;
						case 17:
							sx = "10000" + t;
							break;
						case 18:
							sx = "1000" + t;
							break;
						case 19:
							sx = "100" + t;
							break;
						case 20:
							sx = "10" + t;
							break;
						case 21:
							sx = '1' + t;
							break;
					}
				}
				else sx = Long.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Format method for the o conversion character and int argument.
		 * 
		 * For o format, the flag character '-', means that the output should be left justified within the field. The default is to pad with blanks on
		 * the left. The '#' flag character means that the output begins with a leading 0 and the precision is increased by 1.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is to add no padding. Padding is with blanks by
		 * default.
		 * 
		 * The precision, if set, is the minimum number of digits to appear. Padding is with leading 0s.
		 * 
		 * @param x
		 *            the int to format.
		 * @return the formatted String.
		 */
		private String printOFormat(int x) {
			String sx = null;
			if (x == Integer.MIN_VALUE) sx = "20000000000";
			else
				if (x < 0) {
					String t = Integer.toString((~(-x - 1)) ^ Integer.MIN_VALUE, 8);
					switch (t.length()) {
						case 1:
							sx = "2000000000" + t;
							break;
						case 2:
							sx = "200000000" + t;
							break;
						case 3:
							sx = "20000000" + t;
							break;
						case 4:
							sx = "2000000" + t;
							break;
						case 5:
							sx = "200000" + t;
							break;
						case 6:
							sx = "20000" + t;
							break;
						case 7:
							sx = "2000" + t;
							break;
						case 8:
							sx = "200" + t;
							break;
						case 9:
							sx = "20" + t;
							break;
						case 10:
							sx = '2' + t;
							break;
						case 11:
							sx = '3' + t.substring(1);
							break;
					}
				}
				else sx = Integer.toString(x, 8);
			return printOFormat(sx);
		}

		/**
		 * Utility method for formatting using the o conversion character.
		 * 
		 * @param sx
		 *            the String to format, the result of converting a short, int, or long to a String.
		 * @return the formatted String.
		 */
		private String printOFormat(String sx) {
			int nLeadingZeros = 0;
			int nBlanks = 0;
			if (sx.equals("0") && this.precisionSet && this.precision == 0) sx = "";
			if (this.precisionSet) nLeadingZeros = this.precision - sx.length();
			if (this.alternateForm) nLeadingZeros++;
			if (nLeadingZeros < 0) nLeadingZeros = 0;
			if (this.fieldWidthSet) nBlanks = this.fieldWidth - nLeadingZeros - sx.length();
			if (nBlanks < 0) nBlanks = 0;
			int n = nLeadingZeros + sx.length() + nBlanks;
			char[] ca = new char[n];
			int i;
			if (this.leftJustify) {
				for (i = 0; i < nLeadingZeros; i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
				for (int j = 0; j < nBlanks; j++, i++)
					ca[i] = ' ';
			}
			else {
				if (this.leadingZeros) for (i = 0; i < nBlanks; i++)
					ca[i] = '0';
				else for (i = 0; i < nBlanks; i++)
					ca[i] = ' ';
				for (int j = 0; j < nLeadingZeros; j++, i++)
					ca[i] = '0';
				char[] csx = sx.toCharArray();
				for (int j = 0; j < csx.length; j++, i++)
					ca[i] = csx[j];
			}
			return new String(ca);
		}

		/**
		 * Format method for the c conversion character and char argument.
		 * 
		 * The only flag character that affects c format is the '-', meaning that the output should be left justified within the field. The default is
		 * to pad with blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. Padding is with blanks by default. The default width is 1.
		 * 
		 * The precision, if set, is ignored.
		 * 
		 * @param x
		 *            the char to format.
		 * @return the formatted String.
		 */
		private String printCFormat(char x) {
			int nPrint = 1;
			int width = this.fieldWidth;
			if (!this.fieldWidthSet) width = nPrint;
			char[] ca = new char[width];
			int i = 0;
			if (this.leftJustify) {
				ca[0] = x;
				for (i = 1; i <= width - nPrint; i++)
					ca[i] = ' ';
			}
			else {
				for (i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				ca[i] = x;
			}
			return new String(ca);
		}

		/**
		 * Format method for the s conversion character and String argument.
		 * 
		 * The only flag character that affects s format is the '-', meaning that the output should be left justified within the field. The default is
		 * to pad with blanks on the left.
		 * 
		 * The field width is treated as the minimum number of characters to be printed. The default is the smaller of the number of characters in the
		 * the input and the precision. Padding is with blanks by default.
		 * 
		 * The precision, if set, specifies the maximum number of characters to be printed from the string. A null digit string is treated as a 0. The
		 * default is not to set a maximum number of characters to be printed.
		 * 
		 * @param x
		 *            the String to format.
		 * @return the formatted String.
		 */
		private String printSFormat(String x) {
			int nPrint = x.length();
			int width = this.fieldWidth;
			if (this.precisionSet && nPrint > this.precision) nPrint = this.precision;
			if (!this.fieldWidthSet) width = nPrint;
			int n = 0;
			if (width > nPrint) n += width - nPrint;
			if (nPrint >= x.length()) n += x.length();
			else n += nPrint;
			char[] ca = new char[n];
			int i = 0;
			if (this.leftJustify) {
				if (nPrint >= x.length()) {
					char[] csx = x.toCharArray();
					for (i = 0; i < x.length(); i++)
						ca[i] = csx[i];
				}
				else {
					char[] csx = x.substring(0, nPrint).toCharArray();
					for (i = 0; i < nPrint; i++)
						ca[i] = csx[i];
				}
				for (int j = 0; j < width - nPrint; j++, i++)
					ca[i] = ' ';
			}
			else {
				for (i = 0; i < width - nPrint; i++)
					ca[i] = ' ';
				if (nPrint >= x.length()) {
					char[] csx = x.toCharArray();
					for (int j = 0; j < x.length(); i++, j++)
						ca[i] = csx[j];
				}
				else {
					char[] csx = x.substring(0, nPrint).toCharArray();
					for (int j = 0; j < nPrint; i++, j++)
						ca[i] = csx[j];
				}
			}
			return new String(ca);
		}

		/**
		 * Check for a conversion character. If it is there, store it.
		 * 
		 * @return <code>true</code> if the conversion character is there, and <code>false</code> otherwise.
		 */
		private boolean setConversionCharacter() {
			/* idfgGoxXeEcs */
			boolean ret = false;
			this.conversionCharacter = '\0';
			if (this.pos < this.fmt.length()) {
				char c = this.fmt.charAt(this.pos);
				if (c == 'i' || c == 'd' || c == 'f' || c == 'g' || c == 'G' || c == 'o' || c == 'x' || c == 'X' || c == 'e' || c == 'E' || c == 'c'
						|| c == 's' || c == '%') {
					this.conversionCharacter = c;
					this.pos++;
					ret = true;
				}
			}
			return ret;
		}

		/**
		 * Check for an h, l, or L in a format. An L is used to control the minimum number of digits in an exponent when using floating point formats.
		 * An l or h is used to control conversion of the input to a long or short, respectively, before formatting. If any of these is present, store
		 * them.
		 */
		private void setOptionalHL() {
			this.optionalh = false;
			this.optionall = false;
			this.optionalL = false;
			if (this.pos < this.fmt.length()) {
				char c = this.fmt.charAt(this.pos);
				if (c == 'h') {
					this.optionalh = true;
					this.pos++;
				}
				else
					if (c == 'l') {
						this.optionall = true;
						this.pos++;
					}
					else
						if (c == 'L') {
							this.optionalL = true;
							this.pos++;
						}
			}
		}

		/**
		 * Set the precision.
		 */
		private void setPrecision() {
			int firstPos = this.pos;
			this.precisionSet = false;
			if (this.pos < this.fmt.length() && this.fmt.charAt(this.pos) == '.') {
				this.pos++;
				if ((this.pos < this.fmt.length()) && (this.fmt.charAt(this.pos) == '*')) {
					this.pos++;
					if (!setPrecisionArgPosition()) {
						this.variablePrecision = true;
						this.precisionSet = true;
					}
					return;
				}
				else {
					while (this.pos < this.fmt.length()) {
						char c = this.fmt.charAt(this.pos);
						if (Character.isDigit(c)) this.pos++;
						else break;
					}
					if (this.pos > firstPos + 1) {
						String sz = this.fmt.substring(firstPos + 1, this.pos);
						this.precision = Integer.parseInt(sz);
						this.precisionSet = true;
					}
				}
			}
		}

		/**
		 * Set the field width.
		 */
		private void setFieldWidth() {
			int firstPos = this.pos;
			this.fieldWidth = 0;
			this.fieldWidthSet = false;
			if ((this.pos < this.fmt.length()) && (this.fmt.charAt(this.pos) == '*')) {
				this.pos++;
				if (!setFieldWidthArgPosition()) {
					this.variableFieldWidth = true;
					this.fieldWidthSet = true;
				}
			}
			else {
				while (this.pos < this.fmt.length()) {
					char c = this.fmt.charAt(this.pos);
					if (Character.isDigit(c)) this.pos++;
					else break;
				}
				if (firstPos < this.pos && firstPos < this.fmt.length()) {
					String sz = this.fmt.substring(firstPos, this.pos);
					this.fieldWidth = Integer.parseInt(sz);
					this.fieldWidthSet = true;
				}
			}
		}

		/**
		 * Store the digits <code>n</code> in %n$ forms.
		 */
		private void setArgPosition() {
			int xPos;
			for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
				if (!Character.isDigit(this.fmt.charAt(xPos))) break;
			}
			if (xPos > this.pos && xPos < this.fmt.length()) {
				if (this.fmt.charAt(xPos) == '$') {
					this.positionalSpecification = true;
					this.argumentPosition = Integer.parseInt(this.fmt.substring(this.pos, xPos));
					this.pos = xPos + 1;
				}
			}
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setFieldWidthArgPosition() {
			boolean ret = false;
			int xPos;
			for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
				if (!Character.isDigit(this.fmt.charAt(xPos))) break;
			}
			if (xPos > this.pos && xPos < this.fmt.length()) {
				if (this.fmt.charAt(xPos) == '$') {
					this.positionalFieldWidth = true;
					this.argumentPositionForFieldWidth = Integer.parseInt(this.fmt.substring(this.pos, xPos));
					this.pos = xPos + 1;
					ret = true;
				}
			}
			return ret;
		}

		/**
		 * Store the digits <code>n</code> in *n$ forms.
		 */
		private boolean setPrecisionArgPosition() {
			boolean ret = false;
			int xPos;
			for (xPos = this.pos; xPos < this.fmt.length(); xPos++) {
				if (!Character.isDigit(this.fmt.charAt(xPos))) break;
			}
			if (xPos > this.pos && xPos < this.fmt.length()) {
				if (this.fmt.charAt(xPos) == '$') {
					this.positionalPrecision = true;
					this.argumentPositionForPrecision = Integer.parseInt(this.fmt.substring(this.pos, xPos));
					this.pos = xPos + 1;
					ret = true;
				}
			}
			return ret;
		}

		boolean isPositionalSpecification() {
			return this.positionalSpecification;
		}

		int getArgumentPosition() {
			return this.argumentPosition;
		}

		boolean isPositionalFieldWidth() {
			return this.positionalFieldWidth;
		}

		int getArgumentPositionForFieldWidth() {
			return this.argumentPositionForFieldWidth;
		}

		boolean isPositionalPrecision() {
			return this.positionalPrecision;
		}

		int getArgumentPositionForPrecision() {
			return this.argumentPositionForPrecision;
		}

		/**
		 * Set flag characters, one of '-+#0 or a space.
		 */
		private void setFlagCharacters() {
			/* '-+ #0 */
			this.thousands = false;
			this.leftJustify = false;
			this.leadingSign = false;
			this.leadingSpace = false;
			this.alternateForm = false;
			this.leadingZeros = false;
			for (; this.pos < this.fmt.length(); this.pos++) {
				char c = this.fmt.charAt(this.pos);
				if (c == '\'') this.thousands = true;
				else
					if (c == '-') {
						this.leftJustify = true;
						this.leadingZeros = false;
					}
					else
						if (c == '+') {
							this.leadingSign = true;
							this.leadingSpace = false;
						}
						else
							if (c == ' ') {
								if (!this.leadingSign) this.leadingSpace = true;
							}
							else
								if (c == '#') this.alternateForm = true;
								else
									if (c == '0') {
										if (!this.leftJustify) this.leadingZeros = true;
									}
									else break;
			}
		}

		/**
		 * The integer portion of the result of a decimal conversion (i, d, u, f, g, or G) will be formatted with thousands' grouping characters. For
		 * other conversions the flag is ignored.
		 */
		private boolean thousands = false;
		/**
		 * The result of the conversion will be left-justified within the field.
		 */
		private boolean leftJustify = false;
		/**
		 * The result of a signed conversion will always begin with a sign (+ or -).
		 */
		private boolean leadingSign = false;
		/**
		 * Flag indicating that left padding with spaces is specified.
		 */
		private boolean leadingSpace = false;
		/**
		 * For an o conversion, increase the precision to force the first digit of the result to be a zero. For x (or X) conversions, a non-zero
		 * result will have 0x (or 0X) prepended to it. For e, E, f, g, or G conversions, the result will always contain a radix character, even if no
		 * digits follow the point. For g and G conversions, trailing zeros will not be removed from the result.
		 */
		private boolean alternateForm = false;
		/**
		 * Flag indicating that left padding with zeroes is specified.
		 */
		private boolean leadingZeros = false;
		/**
		 * Flag indicating that the field width is *.
		 */
		private boolean variableFieldWidth = false;
		/**
		 * If the converted value has fewer bytes than the field width, it will be padded with spaces or zeroes.
		 */
		private int fieldWidth = 0;
		/**
		 * Flag indicating whether or not the field width has been set.
		 */
		private boolean fieldWidthSet = false;
		/**
		 * The minimum number of digits to appear for the d, i, o, u, x, or X conversions. The number of digits to appear after the radix character
		 * for the e, E, and f conversions. The maximum number of significant digits for the g and G conversions. The maximum number of bytes to be
		 * printed from a string in s and S conversions.
		 */
		private int precision = 0;
		/** Default precision. */
		private final static int defaultDigits = 6;
		/**
		 * Flag indicating that the precision is *.
		 */
		private boolean variablePrecision = false;
		/**
		 * Flag indicating whether or not the precision has been set.
		 */
		private boolean precisionSet = false;
		/*
     */
		private boolean positionalSpecification = false;
		private int argumentPosition = 0;
		private boolean positionalFieldWidth = false;
		private int argumentPositionForFieldWidth = 0;
		private boolean positionalPrecision = false;
		private int argumentPositionForPrecision = 0;
		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion character applies to a type short int.
		 */
		private boolean optionalh = false;
		/**
		 * Flag specifying that a following d, i, o, u, x, or X conversion character applies to a type lont int argument.
		 */
		private boolean optionall = false;
		/**
		 * Flag specifying that a following e, E, f, g, or G conversion character applies to a type double argument. This is a noop in Java.
		 */
		private boolean optionalL = false;
		/** Control string type. */
		private char conversionCharacter = '\0';
		/**
		 * Position within the control string. Used by the constructor.
		 */
		private int pos = 0;
		/** Literal or control format string. */
		private String fmt;
	}

	/** Vector of control strings and format literals. */
	private ArrayList<ConversionSpecification> vFmt = new ArrayList<ConversionSpecification>();

	/** Character position. Used by the constructor. */
	private int cPos = 0;
	/** Character position. Used by the constructor. */
	private DecimalFormatSymbols dfs = null;
}
